from abc import ABC, abstractmethod
from datetime import datetime

class AbstractAssignable(ABC):
    """抽象基类,定义作业和测验的通用接口"""
    def __init__(self, assignable_id, title, due_date_str, course):
        self.assignable_id = assignable_id
        self.title = title
        # 将日期字符串转换为datetime对象 - 改进为支持多种格式
        try:
            # 尝试解析包含时分的格式
            self.due_date = datetime.strptime(due_date_str, "%Y-%m-%d %H:%M")
        except ValueError:
            try:
                # 尝试解析只有日期的格式
                self.due_date = datetime.strptime(due_date_str, "%Y-%m-%d")
            except ValueError:
                try:
                    # 尝试其他常见格式
                    self.due_date = datetime.strptime(due_date_str, "%Y/%m/%d")
                except ValueError:
                    try:
                        self.due_date = datetime.strptime(due_date_str, "%Y/%m/%d %H:%M")
                    except ValueError:
                        try:
                            # 添加对ISO格式的支持
                            self.due_date = datetime.strptime(due_date_str, "%Y-%m-%dT%H:%M:%S")
                        except ValueError:
                            try:
                                # 添加对带毫秒的ISO格式的支持
                                self.due_date = datetime.strptime(due_date_str, "%Y-%m-%dT%H:%M:%S.%f")
                            except ValueError:
                                # 如果所有格式都失败,抛出详细的错误信息
                                raise ValueError(f"日期格式不正确: {due_date_str}.请使用YYYY-MM-DD、YYYY-MM-DD HH:MM或ISO格式(YYYY-MM-DDTHH:MM:SS)")
                
        self.course = course
        self.submissions = {}  # 存储学生提交,格式:{student_id: submission_details}
        self.submission_count = 0  # 添加这行来初始化提交计数

    def submit(self, student, content):
        """学生提交作业或测验
    
        Args:
            student: 学生对象
            content: 提交内容
        
        Returns:
            tuple: (是否成功, 消息)
        """
        try:
            # 检查学生是否在课程中
            is_enrolled = False
            for enrolled_student in self.course.enrolled_students:
                if enrolled_student.user_id == student.user_id:
                    is_enrolled = True
                    break
            
            if not is_enrolled:
                return False, "You are not enrolled in this course, cannot submit assignment"
            
            # 检查截止日期
            now = datetime.now()
            is_late = now > self.due_date
            
            # 确保submissions属性存在
            if not hasattr(self, 'submissions'):
                self.submissions = {}
            
            # 创建提交记录 - 使用英文状态
            submission_record = {
                "content": content,
                "submit_time": now,
                "is_late": is_late,
                "status": "submitted",
                "score": None,
                "graded_time": None,
                "graded_by": None,
                "comment": ""
            }
            
            # 使用student_id作为键
            student_id = getattr(student, 'student_id', getattr(student, 'user_id', str(student)))
            self.submissions[student_id] = submission_record
            
            # 更新提交计数
            if hasattr(self, 'submission_count'):
                self.submission_count = len(self.submissions)
            else:
                self.submission_count = 1
            
            # 记录提交日志 - 使用英文
            course_name = self.course.course_name if self.course else "Unknown Course"
            print(f"Student {student_id} submitted {self.title} for {course_name}, {'late submission' if is_late else 'submitted on time'}")
            
            # 提交成功后,尝试保存数据
            try:
                # 确保所有提交都能触发数据保存
                from Progress_Tracking_CLI_DataPersistence.lms_main import LMS
                # 检查多种可能的LMS引用方式
                if hasattr(self.course, 'lms') and self.course.lms:
                    self.course.lms.mark_data_changed()  # 使用mark_data_changed方法
                    self.course.lms.save_data()
                elif hasattr(self.course, 'lms_instance') and self.course.lms_instance:
                    self.course.lms_instance.mark_data_changed()
                    self.course.lms_instance.save_data()
                elif hasattr(LMS, 'instance') and LMS.instance:
                    LMS.instance.mark_data_changed()
                    LMS.instance.save_data()
                else:
                    print("警告: 无法自动保存数据,请手动保存")
            except Exception as save_error:
                print(f"保存数据时发生错误: {str(save_error)}")
        
            return True, "作业提交成功" + ("(已截止)" if is_late else "")
        except Exception as e:
            return False, f"作业提交失败: {str(e)}"

    @abstractmethod
    def publish(self):
        """发布任务,返回任务详情字符串"""
        pass

    @abstractmethod
    def check_submission(self, student):
        """检查学生提交是否有效,返回布尔值"""
        pass

    @abstractmethod
    def calculate_score(self, submission):
        """计算提交的分数,返回浮点数"""
        pass

class Assignment(AbstractAssignable):
    """作业类,继承自抽象基类"""
    def __init__(self, assignment_id, assignment_title, assignment_content, due_date_str, course, required_format, total_points=100):
        # 使用assignment_id作为assignable_id
        super().__init__(assignment_id, assignment_title, due_date_str, course)
        self.assignment_content = assignment_content
        self.required_format = required_format
        self.total_points = total_points

    @property
    def assignment_id(self):
        return self.assignable_id

    def publish(self):
        """发布作业,返回作业详情"""
        return (f"Assignment Published: ID={self.assignable_id}, Title={self.title}, "
                f"Due Date={self.due_date.strftime('%Y-%m-%d %H:%M')}, Course={self.course.course_name}, "
                f"Format={self.required_format}")

    def check_submission(self, student):
        """检查作业提交是否有效(是否提交、是否按时、格式是否正确)"""
        student_id = student.student_id
        if student_id not in self.submissions:
            return False
        submission = self.submissions[student_id]
        submit_time = submission["submit_time"]
        # 检查是否迟交
        if submit_time > self.due_date:
            submission["is_late"] = True
            return False
        # 检查格式是否正确
        if "format" in submission and submission["format"] != self.required_format:
            return False
        submission["is_late"] = False
        return True

    def calculate_score(self, submission):
        """简单示例:按内容长度计算分数,实际可替换为更复杂的评分逻辑"""
        content_length = len(submission.get("content", ""))
        # 假设500字及以上得满分100,否则按比例
        return min(100, content_length / 5) if content_length > 0 else 0
    
    def to_dict(self):
        """将Assignment对象序列化为字典"""
        result = {
            "assignment_id": self.assignable_id,
            "title": self.title,
            "content": getattr(self, 'assignment_content', ""),
            "due_date": self.due_date.isoformat(),
            "course_id": self.course.course_id if self.course else None,
            "required_format": getattr(self, 'required_format', ""),
            "total_points": getattr(self, 'total_points', 100),
            "teacher_id": self.course.teacher_id if hasattr(self.course, 'teacher_id') else None,
            "submissions": {}
        }
        
        # 确保submissions是字典并且正确序列化
        if hasattr(self, 'submissions') and self.submissions is not None:
            for student_id, submission in self.submissions.items():
                if isinstance(submission, dict):
                    # 创建提交记录的副本,避免修改原始数据
                    submission_copy = submission.copy()
                    # 序列化提交时间
                    if "submit_time" in submission_copy:
                        if hasattr(submission_copy["submit_time"], "isoformat"):
                            submission_copy["submit_time"] = submission_copy["submit_time"].isoformat()
                        elif isinstance(submission_copy["submit_time"], str):
                            # 如果已经是字符串,保持不变
                            pass
                    
                    # 序列化graded_time
                    if "graded_time" in submission_copy and submission_copy["graded_time"] is not None:
                        if hasattr(submission_copy["graded_time"], "isoformat"):
                            submission_copy["graded_time"] = submission_copy["graded_time"].isoformat()
                    
                    # 确保状态值统一为英文
                    if "status" in submission_copy and submission_copy["status"] == "已提交":
                        submission_copy["status"] = "submitted"
                    
                    # 避免保存对象引用,只保存ID
                    if "course" in submission_copy:
                        submission_copy.pop("course")
                    
                    result["submissions"][student_id] = submission_copy
    
        return result

 
    @property
    def title(self):
        return self._title
    
    @title.setter
    def title(self, value):
        if value and isinstance(value, str):
            self._title = value
    
    # 添加assignment_content属性的setter方法
    @property
    def assignment_content(self):
        return self._assignment_content
    
    @assignment_content.setter
    def assignment_content(self, value):
        if isinstance(value, str):
            self._assignment_content = value
    
    @classmethod
    def from_dict(cls, data, courses):
        """从字典创建作业对象"""
        # 查找对应的课程对象
        course = None
        for c in courses:
            if c.course_id == data["course_id"]:
                course = c
                break
        
        if not course:
            raise ValueError(f"无法找到课程ID: {data['course_id']}")
            
        assignment = cls(
            assignment_id=data["assignment_id"],
            assignment_title=data["title"],
            assignment_content=data["content"],
            due_date_str=data["due_date"],
            course=course,
            required_format=data["required_format"],
            total_points=data["total_points"]
        )
        return assignment

class  Quiz(AbstractAssignable):
    """测验类,继承自抽象基类"""
    def __init__(self, quiz_id, quiz_title, questions, due_date_str, course, time_limit):
        super().__init__(quiz_id, quiz_title, due_date_str, course)
        self.questions = questions  # 格式:[{"id": "Q1", "text": "...", "correct_answer": "...", "points": ...}, ...]
        self.time_limit = time_limit  # 分钟

    def publish(self):
        """发布测验,返回测验详情"""
        return (f"Quiz Published: ID={self.assignable_id}, Title={self.title}, "
                f"Due Date={self.due_date.strftime('%Y-%m-%d %H:%M')}, Course={self.course.course_name}, "
                f"Time Limit={self.time_limit} mins, Total Points={sum(q['points'] for q in self.questions)}")

    def check_submission(self, student):
        """检查测验提交是否有效(是否提交、是否按时、是否答完所有题)"""
        student_id = student.student_id
        if student_id not in self.submissions:
            return False
        submission = self.submissions[student_id]
        submit_time = submission["submit_time"]
        if submit_time > self.due_date:
            submission["is_late"] = True
            return False
        # 检查是否答完所有题
        if len(submission.get("answers", [])) != len(self.questions):
            return False
        submission["is_late"] = False
        return True

    def calculate_score(self, submission):
        """自动判分:对比学生答案和正确答案,计算得分"""
        answers = submission.get("answers", [])
        score = 0
        for i, q in enumerate(self.questions):
            if i < len(answers) and answers[i] == q["correct_answer"]:
                score += q["points"]
        return score
    
